from Pyro.EventService.Clients import Publisher
from threading import Thread
import Pyro.core, Pyro.naming, Pyro.EventService.Server 
import config, connvalidator, crowd, urllib2

class Blender(Pyro.core.SynchronizedObjBase):
    def __init__(self):
        Pyro.core.SynchronizedObjBase.__init__(self)  
         
    def login(self, proxy_port, public_key):
        localStorage = self.getLocalStorage()
        caller = localStorage.caller   # TCPConnection of the client which is connecting
        host = caller.addr[0]
        host_port = (host, proxy_port)
        login = caller.authenticated
        jondo = crowd.Node(host_port, public_key)
        if not self.daemon.crowd.check_in(login, jondo):
            return None     #user has already been logged into the blender: login rejected!
        else:
            if caller.authenticated:
                self.daemon.crowd.add_waiting_list(login, jondo)
                return self.daemon.crowd.get_active_members()
            else:
                return None
                    
    def get_active_members(self):
        return self.daemon.crowd.get_active_members()
             
    def logout(self):
        caller = self.getLocalStorage().caller
        self.daemon.crowd.remove(caller.addr[0])
        
    def get_public_ip(self):
        caller = self.getLocalStorage().caller
        return caller.addr[0]

####################### EVENT SERVER LISTENER #################

class EventPublisher(Pyro.core.ObjBase, Publisher):
    def __init__(self):
        Pyro.core.ObjBase.__init__(self)
        Publisher.__init__(self)
                        
    def raise_event(self, event_name, message):
        self.publish(event_name, message)


####################### NS, ES, DAEMON, EVENT LISTENER THREADS ############

class NameServer(Thread):
    def __init__(self):
        Thread.__init__(self, name="NameServer")
        self.setDaemon(1)
        self.starter = Pyro.naming.NameServerStarter()  # no special identification
                
    def run(self):
        print "Launching Pyro Name Server"
        self.starter.start()
                
    def waitUntilStarted(self):
        return self.starter.waitUntilStarted()
    
        
class EventServer(Thread):
    def __init__(self):
        Thread.__init__(self, name="EventServer")
        self.setDaemon(1)
        self.starter = Pyro.EventService.Server.EventServiceStarter()  # no special identification
        
    def run(self):
        print "Launching Pyro Event Server"
        # we're using the OS's automatic port allocation
        es_port=0 
        self.starter.start(port=es_port, norange=(es_port==0))
                
    def waitUntilStarted(self):
        return self.starter.waitUntilStarted()
    

class PyroServer(Thread):  #the class which must publish objects!
    def __init__(self):
        Thread.__init__(self, name="PyroServer")
        self.setDaemon(1)
        self.ready=0
                
    def run(self):
        Pyro.core.initServer()
        print "Creating Pyro server objects and Pyro Daemon"
        # we're using the OS's automatic port allocation
        port = config.PYRO_SERVER_PORT 
        daemon = Pyro.core.Daemon(port=port, norange=(port==0))
        validator = connvalidator.UserLoginConnValidator()    
        daemon.setNewConnectionValidator(validator)   #user custom connection validation
        daemon.useNameServer(Pyro.naming.NameServerLocator().getNS())
        uri = daemon.connect(Blender(), "Blender")
        print "The Blender's uri for client's connection is: ", uri
        daemon.connect(EventPublisher(), "EventPublisher")
        self.ready = 1
        daemon.crowd = crowd.Crowd()
        self.blender_daemon = daemon
        daemon.requestLoop()
        


        

